package cn.neo.support.iv.fresco.config;

import android.content.Context;
import android.graphics.Bitmap;
import android.os.Environment;

import com.facebook.cache.disk.DiskCacheConfig;
import com.facebook.common.disk.NoOpDiskTrimmableRegistry;
import com.facebook.common.internal.Supplier;
import com.facebook.common.memory.MemoryTrimType;
import com.facebook.common.memory.MemoryTrimmable;
import com.facebook.common.memory.NoOpMemoryTrimmableRegistry;
import com.facebook.common.util.ByteConstants;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.backends.okhttp3.OkHttpImagePipelineConfigFactory;
import com.facebook.imagepipeline.cache.MemoryCacheParams;
import com.facebook.imagepipeline.core.ImagePipelineConfig;

import java.io.File;

import okhttp3.OkHttpClient;


/**
 * <b>Name:</b>Fresco的图片管道配置<br>
 * <b>Author:</b> WK（wangkun@xjzhicheng.com)<br>
 * <b>Date:</b> 2016-12-26<br>
 * <b>Describe:</b>设置管道的相关设置<br>
 * <b>Version:</b>V1.0<br>
 * <b>Revision History:</b><br>
 */
public class ImageLoaderConfig {

    //小图所放路径的文件夹名
    private static final String IMAGE_PIPELINE_SMALL_CACHE_DIR = "ImagePipelineCacheSmall";
    //默认图所放路径的文件夹名
    private static final String IMAGE_PIPELINE_CACHE_DIR = "ImagePipelineCacheDefault";
    //分配的可用内存
    private static final int MAX_HEAP_SIZE = (int) Runtime.getRuntime().maxMemory();
    //使用的缓存数量
    private static final int MAX_MEMORY_CACHE_SIZE = MAX_HEAP_SIZE / 4;
    //小图极低磁盘空间缓存的最大值（特性：可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图）
    private static final int MAX_SMALL_DISK_VERYLOW_CACHE_SIZE = 20 * ByteConstants.MB;
    //小图低磁盘空间缓存的最大值（特性：可将大量的小图放到额外放在另一个磁盘空间防止大图占用磁盘空间而删除了大量的小图）
    private static final int MAX_SMALL_DISK_LOW_CACHE_SIZE = 60 * ByteConstants.MB;
    //默认图极低磁盘空间缓存的最大值
    private static final int MAX_DISK_CACHE_VERYLOW_SIZE = 20 * ByteConstants.MB;
    //默认图低磁盘空间缓存的最大值
    private static final int MAX_DISK_CACHE_LOW_SIZE = 60 * ByteConstants.MB;
    //默认图磁盘缓存的最大值
    private static final int MAX_DISK_CACHE_SIZE = 100 * ByteConstants.MB;

    private static ImagePipelineConfig sImagePipelineConfig;

    public static ImagePipelineConfig getImagePipelineConfig(Context context) {

        if (sImagePipelineConfig == null) {
            /**
             * 推荐缓存到应用本身的缓存文件夹，这么做的好处是:
             * 1、当应用被用户卸载后能自动清除缓存，增加用户好感（可能以后用得着时，还会想起我）
             * 2、一些内存清理软件可以扫描出来，进行内存的清理
             */
            File smallCacheDir = context.getApplicationContext().getExternalCacheDir();
            File mainCacheDir = context.getApplicationContext().getExternalFilesDir(Environment.DIRECTORY_PICTURES);


            //内存配置
            final MemoryCacheParams bitmapCacheParams = new MemoryCacheParams(
                    MAX_MEMORY_CACHE_SIZE,// 内存缓存中总图片的最大大小,以字节为单位。
                    Integer.MAX_VALUE,// 内存缓存中图片的最大数量。
                    MAX_MEMORY_CACHE_SIZE,// 内存缓存中准备清除但尚未被删除的总图片的最大大小,以字节为单位。
                    Integer.MAX_VALUE,// 内存缓存中准备清除的总图片的最大数量。
                    Integer.MAX_VALUE);// 内存缓存中单个图片的最大大小。

            //修改内存图片缓存数量，空间策略（这个方式有点恶心）
            Supplier<MemoryCacheParams> mSupplierMemoryCacheParams = new Supplier<MemoryCacheParams>() {
                @Override
                public MemoryCacheParams get() {
                    return bitmapCacheParams;
                }
            };

            //小图片的磁盘配置
            DiskCacheConfig diskSmallCacheConfig = DiskCacheConfig.newBuilder(context)
                    .setBaseDirectoryPath(smallCacheDir)//缓存图片基路径
                    .setBaseDirectoryName(IMAGE_PIPELINE_SMALL_CACHE_DIR)//文件夹名
                    .setMaxCacheSize(MAX_DISK_CACHE_SIZE)//默认缓存的最大大小。
                    .setMaxCacheSizeOnLowDiskSpace(MAX_SMALL_DISK_LOW_CACHE_SIZE)//缓存的最大大小,使用设备时低磁盘空间。
                    .setMaxCacheSizeOnVeryLowDiskSpace(MAX_SMALL_DISK_VERYLOW_CACHE_SIZE)//缓存的最大大小,当设备极低磁盘空间
                    .setDiskTrimmableRegistry(NoOpDiskTrimmableRegistry.getInstance())
                    .build();

            //默认图片的磁盘配置
            DiskCacheConfig diskCacheConfig = DiskCacheConfig.newBuilder(context)
                    .setBaseDirectoryPath(mainCacheDir)//缓存图片基路径
                    .setBaseDirectoryName(IMAGE_PIPELINE_CACHE_DIR)//文件夹名
                    .setMaxCacheSize(MAX_DISK_CACHE_SIZE)//默认缓存的最大大小。
                    .setMaxCacheSizeOnLowDiskSpace(MAX_DISK_CACHE_LOW_SIZE)//缓存的最大大小,使用设备时低磁盘空间。
                    .setMaxCacheSizeOnVeryLowDiskSpace(MAX_DISK_CACHE_VERYLOW_SIZE)//缓存的最大大小,当设备极低磁盘空间
                    .setDiskTrimmableRegistry(NoOpDiskTrimmableRegistry.getInstance())
                    .build();

            //内存紧张策略
            NoOpMemoryTrimmableRegistry.getInstance().registerMemoryTrimmable(new MemoryTrimmable() {
                @Override
                public void trim(MemoryTrimType trimType) {
                    final double suggestedTrimRatio = trimType.getSuggestedTrimRatio();

                    if (MemoryTrimType.OnCloseToDalvikHeapLimit.getSuggestedTrimRatio() == suggestedTrimRatio
                            || MemoryTrimType.OnSystemLowMemoryWhileAppInBackground.getSuggestedTrimRatio() == suggestedTrimRatio
                            || MemoryTrimType.OnSystemLowMemoryWhileAppInForeground.getSuggestedTrimRatio() == suggestedTrimRatio
                            ) {
                        // 清除内存缓存
                        Fresco.getImagePipeline().clearMemoryCaches();
                    }
                }
            });

            //缓存图片配置
            sImagePipelineConfig = OkHttpImagePipelineConfigFactory.newBuilder(context, new OkHttpClient())
                    .setBitmapsConfig(Bitmap.Config.RGB_565)
                    .setBitmapMemoryCacheParamsSupplier(mSupplierMemoryCacheParams)
                    .setSmallImageDiskCacheConfig(diskSmallCacheConfig)
                    .setMainDiskCacheConfig(diskCacheConfig)
                    .setMemoryTrimmableRegistry(NoOpMemoryTrimmableRegistry.getInstance())
                    .setDownsampleEnabled(true)//要不要向下采样,它处理图片的速度比常规的裁剪scaling更快，
                    // 并且同时支持PNG，JPG以及WEP格式的图片，非常强大,与ResizeOptions配合使用
                    .setResizeAndRotateEnabledForNetwork(true)
                    .build();

        }
        return sImagePipelineConfig;
    }

}
